<?php

namespace app\wsns\controller;

use app\BaseController;
use app\wsns\service\RabbitMQConsumer;
use app\wsns\service\RabbitMQProducer;
use think\facade\Log;
use think\facade\Config;
use Predis\Client;

class Red  extends BaseController
{


    public function tr001(){
        $config = Config::get('redis.predis');
        $redis = new Client($config);
        $redis->set('php-name', 'YX');
        //$name = $redis->get('name');
    }


    public function tr002(){
        $config = Config::get('redis.predis');
        $redis = new Client($config);
        $name = $redis->get('php-name');
        echo $name;
    }

    public function tr003(){
        $redis = new Client();
        $redis->watch('php-name');
        $transaction = $redis->multi();
        $transaction->set('php-name', 'new,yx');
        $result = $transaction->exec(); // 返回 null 表示失败
        if($result == null){
            echo '失败';
        }else{
            echo $result;
        }
    }

    //
    public function tr004()
    {
        $client = new Client();
        $lockKey = 'lock:order:123';
        $isLocked = $client->setnx($lockKey, 'locked');

        if ($isLocked) {
            echo "成功获得锁，可以执行操作\n";
            // 执行业务逻辑...
            $client->setex($lockKey, 10, 'locked'); // 可选：设置过期时间防止死锁
        } else {
            echo "获取锁失败，资源正在被使用\n";
        }
    }

    public function tr004a()
    {
        $client = new Client();
        $lockKey = 'lock:order:123';
        $v = $client->get($lockKey);
        if(empty($v)){
            echo "空的";
        }else{
            echo $v;
        }
    }

    public function tr005()
    {
        $redis = new Client();
        $redis->hSet('user:1', 'name', 'lg');
        $redis->hSet('user:1', 'email', 'wangwu@example.com');
        $user = $redis->hGetAll('user:1');     // vs  hmget  多个 但是又不想要所有
        //var_dump(is_array($user)); // 会输出 bool(true)
        //哈哈 不过第一印象很重要 还是你排第一
        return json_encode($user);

    }

    public function tr006(){
        $redis = new Client();
        $redis->pipeline();
        $redis->hSet('user:2', 'name', 'lm');
        $redis->hSet('user:2', 'email', 'wangwu@example.com');
        $redis->exec();
        $user = $redis->hGetAll('user:2');
        return json_encode($user);
    }
    public function tr6(){
        //AI 修正；可以工作
        $redis = new Client();
        $pipe = $redis->pipeline(); // 获取管道对象（某些版本需要）
        $pipe->hSet('user:2', 'name', 'lm');
        $pipe->hSet('user:2', 'email', 'wangwu@example.com');
        $results = $pipe->exec(); // 必须调用 exec()，返回结果数组
        // 现在可以执行普通命令
        $user = $redis->hGetAll('user:2'); // 这里 $redis 是原始客户端
        return json_encode($user);
    }
    public function tr007(){
        $redis = new Client();
        $redis->multi(); // 开启事务
        $redis->hSet('user:2', 'name', 'lm');
        $redis->hSet('user:2', 'email', 'wangwu@example.com');
        $redis->exec();//执行下
        $user = $redis->hGetAll('user:2');
        return json_encode($user);
    }


    // incrby
    //by
    public function tr008(){
        //todo 1开启匿名 增加访问次数。
        //todo 2 增加IP限制（）
        //todo 3 已经登录的情况；则 可以按“code” 记录已登录。 此“手机”再次访问 如果在

        //
        $client = new Client();
        $count = $client->incr('counter:pageviews');
        echo "当前计数: $count"; // 第一次运行输出 1，第二次输出 2，以此类推
    }

    public function tr009(){
        $client = new Client();
        $prefix = 'shard_list';
        $numShards = 3;

        echo "分片列表长度（Lua）：" . $this->getShardedListLengthWithLua($client,$prefix, $numShards) . "\n";
    }

    public function tr010(){
        $client = new Client();
        // 设置一些测试数据
        $client->lpush('shard_list:0', 'a', 'b');
        $client->lpush('shard_list:1', 'c', 'd', 'e');
        $client->lpush('shard_list:2', 'f');
    }

    //11
    public function tr011(){
        $client = new Client();
        $value = $client->lpop('shard_list:0');
        if ($value) {
            echo "处理新任务: " . $value;
        }
    }

    public function tr012(){
        $client = new Client();

        $feed = $client->lrange('shard_list:1', 0, 9);

        foreach ($feed as $item) {
            echo $item . "\n";
        }
    }



    //13  因为老报错 写个简单的 lua+redis
    public function tr13(){
        $client = new Client();
        //说明游泳
        //可以工作1
        //$result = $client->eval("return 100", 0);
        //可以工作2
        //$result=  $client->eval("return redis.call('GET', KEYS[1])", 1, 'php-name');
        //可以工作3
        $result = $client->eval("
                local val1 = redis.call('GET', KEYS[1])
                local val2 = redis.call('GET', KEYS[2])
                return {val1, val2}"
            , 2
            , 'php-name', 'php-name2');

        //echo $result;  变量可以是string 也可以是array
        var_dump($result);
    }

    public function tr14(){
        echo uniqid();
        echo "<br>";
        echo uniqid('user_');
    }

    //http://tp8more/index.php/wsns/red/tr15
    public function tr15(){
        $redis = new Client();
        // 添加一些测试数据
        $redis->zadd('members:game_guild', 0, 'alice');
        $redis->zadd('members:game_guild', 0, 'bob');
        $redis->zadd('members:game_guild', 0, 'charlie');
        $redis->zadd('members:game_guild', 0, 'david');


        // 查询以 'a' 开头的用户
        $results = $this->autocompleteOnPrefix( 'game_guild', 'a');
        print_r($results); // 输出: ['alice']
    }

    function autocompleteOnPrefix(string $guild, string $prefix): array
    {
        $redis = new Client();

        list($start, $end) = $this->findPrefixRange($prefix);

        // 调试：确认 start/end
        // error_log("Start: $start, End: $end");

        $identifier = uniqid('', true);

        $luaScript = <<<'EOF'
local sindex = redis.call('zrank', KEYS[1], ARGV[1])
local eindex = redis.call('zrank', KEYS[1], ARGV[2])

if not sindex or not eindex then
    return {}
end

local index = math.min(sindex + 9, eindex - 1)
redis.call('zrem', KEYS[1], unpack(ARGV))
return redis.call('zrange', KEYS[1], sindex, index)
EOF;

        try {
            $result = $redis->eval(
                $luaScript,
                1,
                'members:' . $guild,
                $start . $identifier,
                $end . $identifier
            );
        } catch (\Exception $e) {
            error_log("Redis EVAL error: " . $e->getMessage());
            return [];
        }

        // 过滤掉临时标记（虽然 zrem 了，但保险起见）
        return array_filter($result ?? [], function ($item) {
            return strpos($item, '{') === false;
        });
    }


    // 示例辅助函数
    function findPrefixRange2(string $prefix): array
    {
        $lastChar = $prefix[-1];
        $nextChar = chr(ord($lastChar) + 1);
        $end = substr($prefix, 0, -1) . $nextChar;

        return [$prefix, $end];
    }

    function findPrefixRange(string $prefix): array
    {
        // 处理空字符串
        if ($prefix === '') {
            return ['', '']; // 或根据业务返回 ['','a'] 等
        }

        $lastChar = $prefix[-1];
        $ordinal = ord($lastChar);

        // 防止 chr(256) 问题
        if ($ordinal >= 255) {
            // 如果最后一个字符已经是 \xFF，无法再 +1
            // 返回原前缀，让调用方处理为 [prefix, +inf) 或其他逻辑
            return [$prefix, $prefix]; // 或 throw new Exception
        }

        $nextChar = chr($ordinal + 1);
        $end = substr($prefix, 0, -1) . $nextChar;

        return [$prefix, $end];
    }



    //LIST  操作
    function getShardedListLengthWithLua($client, $prefix, $numShards) {

        $luaScript = <<<'EOL'
local total = 0
for i = 0, ARGV[1] - 1 do
    local key = KEYS[1] .. ":" .. i
    local len = redis.call('LLEN', key)
    total = total + len
end
return total
EOL;

        $keys = [$prefix];
        $args = [$numShards];

        try {
            return $client->eval($luaScript, $keys, $args);
        } catch (\Exception $e) {
            // 处理 Redis 或 Lua 错误
            throw new \RuntimeException("Failed to get sharded list length: " . $e->getMessage(), 0, $e);
        }
    }







    public function info()
    {

        Log::info('Test log 001');
//        Log::info("red-info");
//        $log = new Log();
//        $log->info("red-info");
        $p = app()->getRuntimePath() . 'log' . DIRECTORY_SEPARATOR ;

        return $p;
    }

    //http://tp8more/index.php/wsns/red/info2
    public function info2()
    {
        phpinfo();
    }

    // 测试redis001
    //http://tp8more/index.php/wsns/red/tr001



    //http://tp8more/index.php/wsns/red/send
        public function send2()
    {
        $producer = new RabbitMQProducer();
        if (!empty($producer)) {
            $producer->send2('normal.queue','php的消息');
        }
        $producer->close();
        return '消息已发送';
       
    }
    // https://www.buildadmin.com/senior/module/event.html
    // 在buildadmin 中 直接写AppInit 方法？

    public function receive()
    {
//        $consumer = new RabbitMQConsumer();
//        $consumer->consume('delayed.queue', function ($message) {
//            $data = json_decode($message, true);
//            // 处理业务逻辑
//            echo "处理数据: " . $data['name'] . "\n";
//        });

        $consumer = new RabbitMQConsumer();
        $consumer->consume('delayed.queue', function ($message) {
            Log::info("消费拿到数据 $message");
            // 处理业务逻辑
            //return  "处理数据: " .$message. "\n";
        });
        //思考 function 里return 有没有意义
    }

    public function AppInit()
    {
        // AppInit 时执行的代码
        Log::info('wsns-red- appinit');
    }

    //todo 商品销售



}